//
// Created by martin on 2/2/22.
//

#ifndef MYMUDUO_DATE_H
#define MYMUDUO_DATE_H

#include "copyable.h"
#include "Types.h"

#include <memory>
#include <time.h>
//struct tm;

namespace muduo
{

/**
 * Julian Date library (Gregorian Calendar)
 */
class Date : public copyable
{
public:

    struct YearMonthDay
    {
        int year;  // [1900..2500]
        int month; // [1..12]
        int day;   // [1..31]
    };

    static const int kDaysPerWeek = 7;
    static const int kJulianDayOf1970_01_01;

    /**
     * Construct an invalid Date.
     */
    Date()
    : julianDayNumber_(0)
    { }

    /**
     * Construct an yyyy-mm-dd Date.
     * month belongs to [1, 12]
     */
    Date(int year, int month, int day);

    /**
     * Constructs a Date from Julian Day Number.
     * @param julianDayNum
     */
    explicit Date(int julianDayNum)
    : julianDayNumber_(julianDayNum)
    { }

    /**
     * Constructs a Date from struct tm
     */
    explicit Date(const struct tm&);

    // Default copy/assignment/dtor are Okay

    void swap(Date& that)
    {
        std::swap(julianDayNumber_, that.julianDayNumber_);
    }

    bool valid() const { return julianDayNumber_ > 0; }

    /**
     * Converts to yyyy-mm-dd format.
     */
    string toIsoString() const;

    struct YearMonthDay yearMonthDay() const;

    int year() const
    {
        return yearMonthDay().year;
    }

    int month() const
    {
        return yearMonthDay().month;
    }

    int day() const
    {
        return yearMonthDay().day;
    }

    // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ]
    int weekDay() const
    {
        return (julianDayNumber_ + 1) % kDaysPerWeek;
    }

    int julianDayNumber() const { return julianDayNumber_; }

private:
    int julianDayNumber_;
};

inline bool operator<(Date x, Date y)
{
    return x.julianDayNumber() < y.julianDayNumber();
}

inline bool operator==(Date x, Date y)
{
    return x.julianDayNumber() == y.julianDayNumber();
}

} // namespace muduo

#endif //MYMUDUO_DATE_H
